#include "BinIns.h"
#include <iostream>
#include <map>
#include <sstream>
#include <string.h>
#include <vector>
using namespace std;

#define PER_INS_BYTESIZE 4
#define PER_BYTE_BITSIZE 8

static int global_labelCount = 0;

// 枚举类型说明：
// enum后面定义的是枚举类型名
// 花括号内部是该枚举类型可以取的值

// 初始化汇编指令集
static void InitAssembleInstructions(vector<string> &assIns)
{
  assIns.clear();

  assIns.push_back("HLT");
  assIns.push_back("JMP");
  assIns.push_back("CJMP");
  assIns.push_back("OJMP");
  assIns.push_back("CALL");
  assIns.push_back("RET");
  assIns.push_back("PUSH");

  assIns.push_back("POP");

  assIns.push_back("LOADB");
  assIns.push_back("LOADW");
  assIns.push_back("STOREB");
  assIns.push_back("STOREW");
  assIns.push_back("LOADI");
  assIns.push_back("NOP");
  assIns.push_back("IN");
  assIns.push_back("OUT");
  assIns.push_back("ADD");
  assIns.push_back("ADDI");
  assIns.push_back("SUB");
  assIns.push_back("SUBI");
  assIns.push_back("MUL");
  assIns.push_back("DIV");
  assIns.push_back("AND");
  assIns.push_back("OR");
  assIns.push_back("NOR");
  assIns.push_back("NOTB");
  assIns.push_back("SAL");
  assIns.push_back("SAR");
  assIns.push_back("EQU");
  assIns.push_back("LT");
  assIns.push_back("LTE");
  assIns.push_back("NOTC");
}

// 初始化
// 指令-参数个数
static void InitInstrctionArgNumber(map<BinIns, int> &insArgNum)
{
  insArgNum.clear();

  insArgNum[BinIns::binHLT] = 0;
  insArgNum[BinIns::binJMP] = 1;
  insArgNum[BinIns::binCJMP] = 1;
  insArgNum[BinIns::binOJMP] = 0;
  insArgNum[BinIns::binCALL] = 1;
  insArgNum[BinIns::binRET] = 0;
  insArgNum[BinIns::binPUSH] = 1;
  insArgNum[BinIns::binPOP] = 1;
  insArgNum[BinIns::binLOADB] = 2;  //
  insArgNum[BinIns::binLOADW] = 2;  //
  insArgNum[BinIns::binSTOREB] = 2; //
  insArgNum[BinIns::binSTOREW] = 2; //
  insArgNum[BinIns::binLOADI] = 2;
  insArgNum[BinIns::binNOP] = 0;
  insArgNum[BinIns::binIN] = 2;
  insArgNum[BinIns::binOUT] = 2;
  insArgNum[BinIns::binADD] = 3;
  insArgNum[BinIns::binADDI] = 2;
  insArgNum[BinIns::binSUB] = 3;
  insArgNum[BinIns::binSUBI] = 2;
  insArgNum[BinIns::binMUL] = 3;
  insArgNum[BinIns::binDIV] = 3;
  insArgNum[BinIns::binAND] = 3;
  insArgNum[BinIns::binOR] = 3;
  insArgNum[BinIns::binNOR] = 3;
  insArgNum[BinIns::binNOTB] = 2;
  insArgNum[BinIns::binSAL] = 3;
  insArgNum[BinIns::binSAR] = 3;
  insArgNum[BinIns::binEQU] = 2;
  insArgNum[BinIns::binLT] = 2;
  insArgNum[BinIns::binLTE] = 2;
  insArgNum[BinIns::binNOTC] = 0;
}

// 建立二进制指令到汇编指令的映射
// 初始化
void InitBinaryToAssemble(const vector<string> &assIns,
                          map<BinIns, string> &binToIns)
{
  binToIns.clear();
  for (auto i = 0; i != assIns.size(); ++i)
  {
    // assIns和BinIns的指令次序一致
    binToIns[static_cast<BinIns>(i)] = assIns[i];
  }
}

string splitStr(string binaryStr)
{
  BinIns opBin; //二进制操作码
  string result = "";
  string element;
  stringstream input(binaryStr);
  string op;
  while (input >> element)
  {
    op = element.substr(0, 8);
    if (op == "00000000" || op == "00000101" || op == "00000011" ||
        op == "00001101" || op == "00011111")
    {
      result = result + op + " ";
    }
    else if (op == "00000001" || op == "00000010" || op == "00000100" ||
             op == "00000110" || op == "00000111" || op == "00001000" ||
             op == "00001001" || op == "00001010" || op == "00001011")
    {
      result = result + op + " " + element.substr(8, 8) + " ";
    }
    else if (op == "00001100" || op == "00001110" || op == "00001111" ||
             op == "00010001" || op == "00010011" || op == "00010001" ||
             op == "00011100" || op == "00011101" || op == "00011110" ||
             op == "00011001")
    {
      result = result + op + " " + element.substr(8, 8) + " " +
               element.substr(16, 8) + " ";
    }
    else
    {
      result = result + op + " " + element.substr(8, 8) + " " +
               element.substr(16, 8) + " " + element.substr(24, 8) + " ";
    }
  }
  return result;
}

// 读入二进制指令
void ReadBinary(vector<string> &bin, string binaryIns)
{
  binaryIns = splitStr(binaryIns); //分割字符串

  bin.clear();
  string element;
  stringstream input(binaryIns);
  while (input >> element)
    bin.push_back(element);
}

//对参数的不同情况进行处理
string argTransfer(const string &op, string arg)
{
  if (arg == "")
    return arg; //无操作数
  else if (op == "JMP" || op == "CJMP" || op == "CALL")
  {
    return arg;
  } //带标签
  else if (op == "IN" || op == "OUT" || op == "ADDI" || op == "SUBI" ||
           op == "LOADI" || op == "LOADB" || op == "LOADW" || op == "STOREB" ||
           op == "STOREW")
  {
    stringstream input(arg);
    string result = "";
    arg = result;
    input >> result;
    arg = arg + "R" + result + " ";
    input >> result;
    arg = arg + result;
    return arg;
  } //操作数与立即数情况
  else
  {
    stringstream input(arg);
    string result = "";
    arg = result;
    while (input >> result)
    {
      arg = arg + "R" + result + " ";
    }
    return arg;
  }
}

// 将读入的二进制指令转换为Instruction形式
void BinaryToAssemble(const vector<string> &bin, vector<string> &ass,
                      const map<BinIns, string> &binToIns,
                      map<BinIns, int> &insArgNum)
{
  ass.clear();
  string binLine;
  for (auto i = 0; i != bin.size(); ++i)
  {
    binLine += bin[i] + '\t';
  }

  // cout << binLine <<endl;

  istringstream sin(binLine);
  string strOp, strArg;
  string op;     //操作符
  string arg;    //参数
  string assIns; //汇编指令
  BinIns opBin;  //二进制操作码
  while (sin >> strOp)
  {
    arg = "";
    opBin = static_cast<BinIns>(stoi(strOp));
    auto cit = binToIns.find(opBin);
    if (cit == binToIns.end())
    {
      throw "Invalid Instruction";
    }
    op = cit->second;
    int argNum = insArgNum[cit->first];
    while (argNum > 0)
    {
      sin >> strArg;
      arg = arg + strArg + " ";
      --argNum;
    }
    arg = argTransfer(op, arg);
    if (op == "JMP" || op == "CJMP" || op == "CALL")
    {
      int index = 0;
      stringstream stream;
      stream << arg;
      stream >> index;
      stream.clear();
      ass[index / PER_INS_BYTESIZE] = "LABEL" +
                                      std::to_string(++global_labelCount) +
                                      ":" + ass[index / PER_INS_BYTESIZE];
      arg = "LABEL" + std::to_string(global_labelCount);
    }
    assIns = op + " " + arg;
    ass.push_back(assIns);
  }
}

// 二进制字符串为十进制字符串
string StringToNum(const string &str)
{
  string ret;
  int num = 0;
  for (auto i = 0; i != str.size(); ++i)
  {
    num = num * 2 + str[i] - '0';
  }
  char tmp[101];
  _itoa_s(num, tmp, 10);
  ret = tmp;
  return ret;
}

// 二进制指令转换为十进制指令
// 针对输入的二进制指令为二进制编码形式的情况
void BinaryToDec(vector<string> &bin)
{
  for (auto i = 0; i != bin.size(); ++i)
  {
    istringstream sin(bin[i]);
    string tmp, ins;
    while (sin >> tmp)
    {
      ins += StringToNum(tmp) + '\t';
    }
    bin[i] = ins;
  }
}

#ifdef __LIB__
// 汇编指令集
static vector<string> AssIns;
// 二进制指令-操作数个数
static map<BinIns, int> insArgNum;
// 二进制到汇编指令的映射
static map<BinIns, string> binToAss;
void InitAntiAssembler()
{
  InitAssembleInstructions(AssIns);

  InitInstrctionArgNumber(insArgNum);

  InitBinaryToAssemble(AssIns, binToAss);
}

/**
 * @brief 二进制指令转汇编指令
 * @param 存放二进制指令的文本
 * @return 转移完成的汇编指令
 */
string Bin2Asm(const string &BinIns)
{
  vector<string> bin;
  ReadBinary(bin, BinIns);
  BinaryToDec(bin);
  vector<string> ass; // 保存转换后的汇编指令
  BinaryToAssemble(bin, ass, binToAss, insArgNum);
  stringstream AsmIns;
  for (const string &item : ass)
  {
    AsmIns << item << '\n';
  }
  global_labelCount = 0;
  return AsmIns.str();
}
#else

// 输出
static void Display(const vector<string> &bar)
{
  for (auto i = 0; i != bar.size(); ++i)
  {
    cout << bar[i] << endl;
  }
}

string BinToAss(const string &binaryIns)
{
  // 汇编指令集
  vector<string> assIns;
  InitAssembleInstructions(assIns);

  // 二进制指令-操作数个数
  map<BinIns, int> insArgNum;
  InitInstrctionArgNumber(insArgNum);

  // 二进制到汇编指令的映射
  map<BinIns, string> binToAss;
  InitBinaryToAssemble(assIns, binToAss);

  //进行二进制指令的转化
  vector<string> bin;
  ReadBinary(bin, binaryIns);
  BinaryToDec(bin);
  vector<string> ass; // 保存转换后的汇编指令
  BinaryToAssemble(bin, ass, binToAss, insArgNum);

  Display(ass);

  cout << endl;
  return "";
}

int main()
{
  string a =
      "00001100000000000000000000000000 00001100000000010000000100000000 "
      "00001100000000100110010000000000 00001100000000110000101000000000 "
      "00001100000001000001111000000000 00010000000000000000000000000001 "
      "00010001000000010000000100000000 00011110000000010000001000000000 "
      "00000010000101000000000000000000 00010101000001000000000100000011 "
      "00010100000001010000001100000100 00010010000001010000000000000101 "
      "00000110000001010000000000000000 00010001000001100000000100000000 "
      "00010000000000010000010000000111 00011101000001110000000100000000 "
      "00000010001001000000000000000000 00000111000000010000000000000000 "
      "00010001000000000011000000000000 00001111000000000000111100000000 "
      "00010011000001100000000100000000 00011101000001110000011000000000 "
      "00000010010001000000000000000000 00000000001100000000000000000000";
  BinToAss(a);
  /*

  vector<string> ass; // 保存转换后的汇编指令
  BinaryToAssemble(bin, ass, binToAss, insArgNum);

  Display(ass);

  cout << endl;
*/
  return 0;
}
#endif
